<html>
<head>
    <script src="../OLLoader.js"></script>
    <script type="text/javascript">

    function test_initialize(t) {
        t.plan(5);

        var options = {
            url: 'http://localhost/wms',
            layers: ["foo"],
            formatOptions: {
                foo: "bar"
            }
        };
        var control = new OpenLayers.Control.WMSGetFeatureInfo(options);
        t.ok(control instanceof OpenLayers.Control.WMSGetFeatureInfo,
             "new OpenLayers.Control.WMSGetFeatureInfo returns an instance");
        t.eq(control.url, 'http://localhost/wms',
             "constructor sets url correctly");
        t.eq(control.layers, ["foo"],
             "constructor layers"
            );
        t.ok(control.format instanceof OpenLayers.Format.WMSGetFeatureInfo, "format created");
        t.eq(control.format.foo, "bar", "format options used")
    }

    function test_clickCallBack_option(t) {
        t.plan(9);

        var control;

        control = new OpenLayers.Control.WMSGetFeatureInfo({
            hover: true
        });
        t.ok(control.handler instanceof OpenLayers.Handler.Hover,
             'constructor creates hover handler');
        t.ok(control.handler.callbacks["move"] === control.cancelHover,
             'constructor registers proper "move" callback in handler');
        t.ok(control.handler.callbacks["pause"] === control.getInfoForHover,
             'constructor registers proper "pause" callback in handler');

        control = new OpenLayers.Control.WMSGetFeatureInfo();
        t.ok(control.handler instanceof OpenLayers.Handler.Click,
             'constructor creates click handler');
        t.ok(control.handler.callbacks["click"] === control.getInfoForClick,
             'constructor registers proper "click" callback in handler');

        control = new OpenLayers.Control.WMSGetFeatureInfo({
            clickCallback: "rightclick"
        });
        t.ok(control.handler.callbacks["rightclick"] === control.getInfoForClick,
             'constructor registers proper "rightclick" callback in handler');

        control = new OpenLayers.Control.WMSGetFeatureInfo({
            clickCallback: "dblclick",
            handlerOptions: {
                click: {
                    "single": false,
                    "double": true
                }
            }
        });
        t.ok(control.handler.callbacks["dblclick"] === control.getInfoForClick,
             'constructor registers proper "dblclick" callback in handler');
        t.eq(control.handler["single"], false,
             'constructor sets "single" to false in handler');
        t.eq(control.handler["double"], true,
             'constructor sets "double" to true in handler');
     }

    function test_destroy(t) {
        t.plan(2);
        var map = new OpenLayers.Map("map");
        var click = new OpenLayers.Control.WMSGetFeatureInfo({
            url: 'http://localhost/wms',
            layers: ["foo"]
        });

        var hover = new OpenLayers.Control.WMSGetFeatureInfo({
            url: 'http://localhost/wms',
            layers: ["foo"],
            hover: true
        });

        click.handler.deactivate = function() {
            t.ok(true,
                 "control.deactivate calls deactivate on click handler");
        };
        hover.handler.deactivate = function() {
            t.ok(true,
                 "control.deactivate calls deactivate on hover handler");
        };
        click.destroy();
        hover.destroy();
    }

    function test_click(t) {
        t.plan(4);
        var map = new OpenLayers.Map('map');

        // mock up active control
        var control = new OpenLayers.Control.WMSGetFeatureInfo();
        map.addControl(control);
        control.activate();

        control.request = function(position) {
            t.eq(position.x, 50,
                 "x position is as expected");
            t.eq(position.y, 50,
                 "y position is as expected");
        };

        control.getInfoForClick({xy: {x: 50, y: 50}});
        control.getInfoForHover({xy: {x: 50, y: 50}});
    }

    function test_getfeatureinfo_event(t) {

        t.plan(5);

        var text =
            '<?xml version="1.0" encoding="UTF-8" ?>' +
            '<FeatureInfoResponse>' +
            '  <FIELDS OBJECTID="1188" HECTARES="1819.734" ZONENR="5854" NULZONES=" " AREA="18197340.1426" PERIMETER="19177.4073627" SHAPE="NULL" SE_ANNO_CAD_DATA="NULL" SHAPE.AREA="0" SHAPE.LEN="0"/>' +
            '</FeatureInfoResponse>';

        var map = new OpenLayers.Map('map');

        var xy;
        var url = "http://foo";

        // mock up a control with output "object" and drillDown true
        var control = new OpenLayers.Control.WMSGetFeatureInfo({
            output: "object",
            drillDown: true,
            request: function(position) {},
            eventListeners: {
                getfeatureinfo: function(evt) {
                    t.ok(evt.features[0].url === url, "features is an object with a property url when output is object");
                    var features = evt.features[0].features;
                    t.ok(features.length === 1, "features properties has a length of 1");
                    t.ok(features[0] instanceof OpenLayers.Feature.Vector, "Feature array contains 1 feature");
                }
            }
        });

        // mock up a control with output "features" and drillDown true
        var control2 = new OpenLayers.Control.WMSGetFeatureInfo({
            autoActivate: true,
            drillDown: true,
            request: function(position) {},
            eventListeners: {
                getfeatureinfo: function(evt) {
                    var features = evt.features;
                    t.ok(features.length === 1, "features properties has a length of 1");
                    t.ok(features[0] instanceof OpenLayers.Feature.Vector, "Feature array contains 1 feature");
                }
            }
        });

        map.addControls([control, control2]);
        control.activate();

        xy = {x: 50, y: 50};
        control._requestCount = control2._requestCount = 0;
        control._numRequests = control2._numRequests = 1;
        control.handleResponse({xy: xy}, {responseText: text}, url);
        control2.handleResponse({xy: xy}, {responseText: text}, url);
        map.destroy();
    }

    function test_beforegetfeatureinfo_event(t) {
        t.plan(2);
        var map = new OpenLayers.Map('map');

        var xy, mode;

        // mock up active control
        var control = new OpenLayers.Control.WMSGetFeatureInfo({
            request: function(position) {},
            eventListeners: {
                beforegetfeatureinfo: function(evt) {
                    t.eq(evt.xy, xy,
                         "beforegetfeatureinfo listener gets " +
                         "expected xy (" + mode + ")");
                }
            }
        });
        map.addControl(control);
        control.activate();

        // 1 test
        mode = "click";
        xy = {x: 50, y: 50};
        control.getInfoForClick({xy: xy});

        // 1 test
        mode = "hover";
        xy = {x: 70, y: 70};
        control.getInfoForHover({xy: xy});
    }

    function test_nogetfeatureinfo_event(t) {
        t.plan(1);
        var map = new OpenLayers.Map('map');
        // mock up active control
        var control = new OpenLayers.Control.WMSGetFeatureInfo({
            eventListeners: {
                nogetfeatureinfo: function(evt) {
                    t.ok((evt.type == "nogetfeatureinfo"), "nogetfeatureinfo listener gets called when there are no queryable layers");
                }
            }
        });
        map.addControl(control);
        control.activate();

        // 1 test
        mode = "click";
        xy = {x: 50, y: 50};
        control.getInfoForClick({xy: xy});
    }

    function test_activate(t) {
        t.plan(4);
        var map = new OpenLayers.Map("map");
        var click = new OpenLayers.Control.WMSGetFeatureInfo({
            url: 'http://localhost/wms',
            featureType: 'type',
            featureNS: 'http://localhost/ns',
            layers: 'ns:type'
        });
        var hover = new OpenLayers.Control.WMSGetFeatureInfo({
            url: 'http://localhost/wms',
            featureType: 'type',
            featureNS: 'http://localhost/ns',
            layers: 'ns:type',
            hover: true
        });
        map.addControl(click);
        map.addControl(hover);
        t.ok(!click.handler.active,
             "click handler is not active prior to activating control");
        t.ok(!hover.handler.active,
             "hover handler is not active prior to activating control");
        click.activate();
        hover.activate();
        t.ok(click.handler.active,
             "click handler is active after activating control");
        t.ok(hover.handler.active,
             "hover handler is active after activating control");
    }

    function test_deactivate(t) {
        t.plan(2);
        var map = new OpenLayers.Map("map");
        var click = new OpenLayers.Control.WMSGetFeatureInfo({
            url: 'http://localhost/wms',
            featureType: 'type',
            featureNS: 'http://localhost/ns',
            layers: 'ns:type'
        });
        var hover = new OpenLayers.Control.WMSGetFeatureInfo({
            url: 'http://localhost/wms',
            featureType: 'type',
            featureNS: 'http://localhost/ns',
            layers: 'ns:type'
        });
        map.addControl(click);
        map.addControl(hover);
        click.activate();
        hover.activate();

        click.handler.deactivate = function() {
            t.ok(true,
                 "control.deactivate calls deactivate on click handler");
            OpenLayers.Handler.Click.prototype.deactivate.apply(this, arguments);
        };
        hover.handler.deactivate = function() {
            t.ok(true,
                 "control.deactivate calls deactivate on hover handler");
            OpenLayers.Handler.Hover.prototype.deactivate.apply(this, arguments);
        };
        click.deactivate();
        hover.deactivate();
    }

    // Verify that things work all right when we combine different types for the STYLES and LAYERS
    // params in the WMS Layers involved
    function test_mixedParams(t) {
        t.plan(5);
        var map = new OpenLayers.Map("map", {
            getExtent: function() {return(new OpenLayers.Bounds(-180,-90,180,90));}
        });
        var geographic = new OpenLayers.Projection("EPSG:4326");

        var a = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", {
            layers: "a,b,c,d",
            styles: "a,b,c,d"
        }, {projection: geographic});

        var b = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", {
            layers: ["a","b","c","d"],
            styles: ["a","b","c","d"]
        }, {projection: geographic});

        var c = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", {
            layers: ["a","b","c","d"]
        });

        var d = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", {
            layers: "a,b,c,d"
        }, {projection: geographic});

        var click = new OpenLayers.Control.WMSGetFeatureInfo({
            featureType: 'type',
            featureNS: 'ns',
            layers: [a, b, c, d]
        }, {projection: geographic});

        map.addControl(click);

        var log = {};
        var _request = OpenLayers.Request.GET;
        OpenLayers.Request.GET = function(options) {
            log.options = options;
        };
        click.activate();
        click.getInfoForClick({xy: {x: 50.2, y: 50.1}});
        OpenLayers.Request.GET = _request;

        t.eq(
            log.options && log.options.params.X,
            50,
            "X should be an integer"
        );

        t.eq(
            log.options && log.options.params.Y,
            50,
            "Y should be an integer" 
        );

        t.eq(
            log.options && log.options.url,
            "http://localhost/wms",
            "url from first layer used"
        );
        t.eq(
            log.options && log.options.params.STYLES.join(","),
            ",,,,,,,,a,b,c,d,a,b,c,d",
            "Styles merged correctly"
        );

        t.eq(
            log.options && log.options.params.FORMAT,
            "image/jpeg",
            "Required 'format' parameter included"
 	    );

    }

    function test_urlMatches(t) {

        t.plan(5);

        var control = new OpenLayers.Control.WMSGetFeatureInfo({
            url: "http://host/wms?one=1&two=2"
        });

        t.ok(!control.urlMatches("foo"), "doesn't match garbage");
        t.ok(control.urlMatches("http://host:80/wms?two=2&one=1"), "matches equivalent url");

        // give the control more urls to match from
        control.layerUrls = ["http://a.host/wms", "http://b.host/wms"];

        t.ok(control.urlMatches("http://host:80/wms?two=2&one=1"), "still matches equivalent url");
        t.ok(control.urlMatches("http://a.host:80/wms"), "matches equivalent of first of layerUrls");
        t.ok(control.urlMatches("http://b.host:80/wms"), "matches equivalent of second of layerUrls");

    }

    function test_layerUrls(t) {

        t.plan(4);
        var map = new OpenLayers.Map({
            div: "map",
            getExtent: function() {
                return new OpenLayers.Bounds(-180,-90,180,90);
            }
        });

        var a = new OpenLayers.Layer.WMS(
            null, "http://a.mirror/wms", {layers: "a"}
        );
        var b = new OpenLayers.Layer.WMS(
            null, "http://b.mirror/wms", {layers: "b"}
        );
        var c = new OpenLayers.Layer.WMS(
            null, ["http://c.mirror/wms", "http://d.mirror/wms"], {layers: "c"}
        );
        map.addLayers([a, b, c]);

        var control = new OpenLayers.Control.WMSGetFeatureInfo({
            url: "http://host/wms",
            layers: [a, b, c]
        });
        map.addControl(control);
        control.activate();

        // log calls to GET
        var log;
        var _request = OpenLayers.Request.GET;
        OpenLayers.Request.GET = function(options) {
            log.options = options;
        };

        // control url doesn't match layer urls, no request issued
        log = {};
        control.getInfoForClick({xy: {x: 50, y: 50}});
        t.ok(!log.options, "no url match, no request issued");

        // give control a list of urls to match
        log = {};
        control.layerUrls = ["http://a.mirror/wms", "http://b.mirror/wms"];
        control.getInfoForClick({xy: {x: 50, y: 50}});
        t.eq(log.options && log.options.url, "http://host/wms", "some match, request issued");
        t.eq(log.options && log.options.params["QUERY_LAYERS"].join(","), "b,a", "selected layers queried");

        // show that a layer can be matched if it has a urls array itself (first needs to be matched)
        log = {};
        control.layerUrls = ["http://c.mirror/wms"];
        control.getInfoForClick({xy: {x: 50, y: 50}});
        t.eq(log.options && log.options.params["QUERY_LAYERS"].join(","), "c", "layer with urls array can be queried");

        // clean up
        OpenLayers.Request.GET = _request;
        map.destroy();

    }
    
    function test_hover(t) {
        
        t.plan(2);
        
        var map = new OpenLayers.Map({
            div: "map",
            layers: [
                new OpenLayers.Layer.WMS(null, "/dummywms", {layers: "one"})
            ],
            center: new OpenLayers.LonLat(0, 0),
            zoom: 1
        });
        
        var control = new OpenLayers.Control.WMSGetFeatureInfo({
            hover: true
        });
        map.addControl(control);
        control.activate();
        
        // mock up a mousemove
        control.getInfoForHover({xy: new OpenLayers.Pixel(10, 10)});
        t.ok(!!control.hoverRequest, "hoverRequest set");
        
        // confirm that request is canceled on next move
        var called = 0;
        control.hoverRequest.abort = function() {
            ++called;
        };
        control.handler.px = null;
        control.handler.mousemove({xy: new OpenLayers.Pixel(20, 20)});
        t.eq(called, 1, "hover request aborted");
        
        map.destroy();
        
    }

    function test_exceptions(t) {
        t.plan(1);
        var map = new OpenLayers.Map("map", {
            getExtent: function() {return(new OpenLayers.Bounds(-180,-90,180,90));}
            }
        );

        var a = new OpenLayers.Layer.WMS("dummy","http://myhost/wms", {
            layers: "x",
            exceptions: "text/xml"
        });

        map.addLayer(a);

        var click = new OpenLayers.Control.WMSGetFeatureInfo({
        });

        map.addControl(click);

        var _request = OpenLayers.Request.GET;
        OpenLayers.Request.GET = function(options) {
            t.eq(options.params["EXCEPTIONS"], "text/xml", "Exceptions parameter taken from the WMS layer if provided");
        };
        click.activate();
        click.getInfoForClick({xy: {x: 50, y: 50}});
        OpenLayers.Request.GET = _request;
        map.destroy();
    }

    function test_drillDown(t) {
        t.plan(6);
        var map = new OpenLayers.Map("map", {
            getExtent: function() {return(new OpenLayers.Bounds(-180,-90,180,90));}
            }
        );

        var a = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", {
            layers: "a"
        });

        var b = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", {
            layers: "c"
        });

        // this service does not support application/vnd.ogc.gml for GetFeatureInfo, only text/xml
        var c = new OpenLayers.Layer.WMS("dummy","http://myhost/wms", {
            layers: "x",
            info_format: "text/xml"
        });

        map.addLayers([a, b, c]);

        var click = new OpenLayers.Control.WMSGetFeatureInfo({
            drillDown: true,
            infoFormat: "application/vnd.ogc.gml"
        });

        map.addControl(click);

        var count = 0;
        var _request = OpenLayers.Request.GET;
        OpenLayers.Request.GET = function(options) {
            count++;
            if (count == 2) {
                t.eq(options.params["INFO_FORMAT"], "application/vnd.ogc.gml", "Default info format of the control is used");
                t.eq(options.params["QUERY_LAYERS"].join(","), "c,a", "Layers should be grouped by service url");
                t.eq(options.url, "http://localhost/wms", "Correct url used for second request");
            } else if (count == 1) {
                t.eq(options.params["INFO_FORMAT"], "text/xml", "Overridden info format is used instead of the control's infoFormat");
                t.eq(options.url, "http://myhost/wms", "Correct url used for first request");
            }
        };
        click.activate();
        click.getInfoForClick({xy: {x: 50, y: 50}});
        OpenLayers.Request.GET = _request;
        t.eq(count, 2, "We expect 2 requests to go off");
        map.destroy();
    }
    
    function test_GetFeatureInfo_buildWMSOptions(t) {
        t.plan(3);
        
        var map = new OpenLayers.Map("map", {
            getExtent: function() {return(new OpenLayers.Bounds(-180,-90,180,90));},
            projection: "EPSG:900913"
        });
        var a = new OpenLayers.Layer.WMS("dummy", "http://localhost/wms", {
            layers: "a"
        }, {projection: "EPSG:3857"});
        var b = new OpenLayers.Layer.WMS("dummy", "http://localhost/wms", {
            layers: "b"
        });
        var c = new OpenLayers.Layer.WMS("dummy", "http://localhost/wms", {
            layers: "c"
        }, {projection: "EPSG:4326"});
        map.addLayers([a, b, c]);
        var gfi = new OpenLayers.Control.WMSGetFeatureInfo();
        map.addControl(gfi);
        gfi.activate();

        var options = gfi.buildWMSOptions("http://localhost/wms", [a], {xy: {x: 50, y: 50}}, "text/html");
        t.eq(options.params.SRS, "EPSG:3857", "layer projection used if provided and equal map projection");

        options = gfi.buildWMSOptions("http://localhost/wms", [b], {xy: {x: 50, y: 50}}, "text/html");
        t.eq(options.params.SRS, "EPSG:900913", "map projection used if layer has no projection configured");

        options = gfi.buildWMSOptions("http://localhost/wms", [b], {xy: {x: 50, y: 50}}, "text/html");
        t.eq(options.params.SRS, "EPSG:900913", "map projection used if layer configured with an incompatible projection");
    }

    function test_GetFeatureInfo_WMS13(t) {
        t.plan(4);
        var map = new OpenLayers.Map("map", {
            getExtent: function() {return(new OpenLayers.Bounds(-180,-90,180,90));}
            }
        );

        var a = new OpenLayers.Layer.WMS(null, "http://localhost/wms", {
            layers: "a",
            version: "1.3.0"
        });
        map.addLayer(a);

        var click = new OpenLayers.Control.WMSGetFeatureInfo({
        });

        map.addControl(click);
        var log = {};
        var _request = OpenLayers.Request.GET;
        OpenLayers.Request.GET = function(options) {
            log.options = options;
        };
        click.activate();
        click.getInfoForClick({xy: {x: 50.1, y: 60.2}});
        OpenLayers.Request.GET = _request;
        t.eq(
            log.options && log.options.params.CRS,
            "EPSG:4326",
            "Since it is WMS 1.3 use CRS parameter instead of SRS in the GetFeatureInfo request"
        );

        t.eq(
            log.options && log.options.params.I,
            50,
            "Since it is WMS 1.3 use I parameter instead of X in the GetFeatureInfo request"
        );

        t.eq(
            log.options && log.options.params.J,
            60,
            "Since it is WMS 1.3 use J parameter instead of Y in the GetFeatureInfo request"
        );

        t.eq(
            log.options && log.options.params.BBOX,
            "-90,-180,90,180",
            "Since it is WMS 1.3 the BBOX should respect axis order"
        );

    }

    </script>
</head>
<body>
    <div id="map" style="width: 400px; height: 250px;"/>
</body>
</html>
